/*
 * Copyright 2007. Mount Sinai Hospital, Toronto, Canada.
 * 
 * Licensed under the GNU Lesser General Public License, Version 2. You
 * can find a copy of the license at:
 * 
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 * 
 * IN NO EVENT SHALL MOUNT SINAI HOSPITAL BE LIABLE TO ANY PARTY FOR DIRECT, 
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 * EVEN IF MOUNT SINAI HOSPITAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 * MOUNT SINAI HOSPITAL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND 
 * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". 
 * MOUNT SINAI HOSPITAL HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 */
package com.sinai.mshab.client.ui.pages;

import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sinai.mshab.client.exception.MissingSidePanelItemIdentificationException;

/**
 * A <code>VerticalSidePanel</code> is a panel which lives inside of a
 * {@link PageContainer}. A <code>VerticalSidePanel</code> is a specialised
 * {@link VerticalPanel} tailored to the needs of a <code>PageContainer</code>.
 * 
 * @author Arthur Kalmenson
 */
public class VerticalSidePanel extends Composite implements SidePanel {

	/**
	 * The CSS class for a panel item that is not active.
	 */
	private static final String PANEL_ITEM_STYLE = "mshabPanelItem";

	/**
	 * The CSS class for a panel item that is active.
	 */
	private static final String ACTIVE_PANEL_ITEM_STYLE = "mshabActivePanelItem";

	/**
	 * The CSS for the panel's header.
	 */
	private static final String PANEL_HEADER_CSS = "mshabPanelHeader";

	/**
	 * The CSS class for the side panel itself.
	 */
	private static final String PANEL_STYLE = "mshab-SidePanel";

	/**
	 * The title of this panel.
	 */
	private Label header;

	/**
	 * Stores the clicked widget.
	 */
	public static Widget clicked;

	/**
	 * The actual panel.
	 */
	private VerticalPanel panel;

	public VerticalSidePanel() {
		panel = new VerticalPanel();
		panel.setStyleName(PANEL_STYLE);
		initWidget(panel);
	}

	/**
	 * Adds the {@link SidePanelItem} <code>item</code> to this panel if it
	 * has a unique identifier. If there already exists a {@link SidePanelItem}
	 * with the same id, that existing side panel will be removed. Furthermore,
	 * if <code>item</code> does not have an id, a
	 * {@link MissingSidePanelItemIdentificationException} will be thrown.
	 * 
	 * @param item
	 *            the panel item to add.
	 */
	public void add(SidePanelItem item) {

		boolean added = false;

		// throw exception if there is no id.
		if (item.getId() == null) {
			throw new MissingSidePanelItemIdentificationException(""
					+ "SidePanelItem does not have an id.");
		}

		// check if such an item already exists, if so, we need to replace it,
		// otherwise we append item.
		for (int i = 0; i < panel.getWidgetCount(); i++) {

			SidePanelItem sidePanelItem = (SidePanelItem) panel.getWidget(i);
			if (sidePanelItem.getId().equals(item.getId())) {
				panel.remove(i);
				panel.insert((Widget) item, i);
				added = true;

				// since we found the item, we can stop looking.
				break;
			}
		}

		if (!added) {
			panel.add((Widget) item);
		}
	}

	public SidePanelItem get(String id) {

		SidePanelItem result = null;

		for (int i = 0; i < panel.getWidgetCount(); i++) {
			SidePanelItem sidePanelItem = (SidePanelItem) panel.getWidget(i);
			if (sidePanelItem.getId().equals(id)) {
				result = sidePanelItem;

				// since we found the item, we can stop looking.
				break;
			}
		}

		return result;
	}

	public int remove(String id) {

		int result = -1;

		for (int i = 0; i < panel.getWidgetCount(); i++) {
			SidePanelItem sidePanelItem = (SidePanelItem) panel.getWidget(i);
			if (sidePanelItem.getId().equals(id)) {

				// found the item. We save the index and remove it.
				panel.remove(i);
				result = i;

				// since we found the item and remove it, we can stop.
				break;
			}
		}

		return result;
	}

	/**
	 * Sets the text of the header of this panel to the provided String.
	 * 
	 * @param header
	 *            the new header.
	 */
	public void setHeader(String header) {
		this.header = new Label(header);
		this.header.setStyleName(PANEL_HEADER_CSS);
		panel.insert(this.header, 0);
	}

	/**
	 * Returns the text of the header associated with this panel.
	 * 
	 * @return the text of the header associated with this panel.
	 */
	public String getHeader() {
		String titleString = null;
		if (header != null) {
			titleString = header.getText();
		}
		return titleString;
	}

	/**
	 * Removes the header of this panel.
	 */
	public void removeHeader() {
		if (header != null) {
			panel.remove(header);
			header = null;
		}
	}

	/**
	 * Makes the panel item with name, <code>name</code>, active.
	 * 
	 * @param name
	 *            the panel to make active.
	 */
	public void makeActive(String name) {
	}

	/**
	 * Activates the <code>clicked</code> widget.
	 */
	public void activateClickedWidget() {
		if (clicked != null) {
			clicked.setStyleName(ACTIVE_PANEL_ITEM_STYLE);
		}
	}

	/**
	 * Removes the active CSS style from every item in this panel.
	 */
	public void clearActiveCSS() {
		for (int i = 0; i < panel.getWidgetCount(); i++) {
			panel.getWidget(i).setStyleName(PANEL_ITEM_STYLE);
		}
	}

	public void clear() {
		panel.clear();
	}

	public int size() {
		return panel.getWidgetCount();
	}

	public boolean isEmpty() {
		return panel.getWidgetCount() == 0;
	}

	/**
	 * A <code>PanelItemListener</code> listens for when a panel item is
	 * clicked and sets the appropriate CSS styles.
	 * 
	 * @author Arthur Kalmenson
	 */
	private class PanelItemListener implements ClickListener {

		public void onClick(Widget sender) {

			// remove the CSS style of every panel item
			clearActiveCSS();

			// add active CSS to the sender.
			clicked = sender;
		}
	}
}
